package xray

import (
	"errors"
	"fmt"
	"gitee.com/gam6it/SecToolkit/utils/http2"
)

type Plan struct {
	client         *Client
	Id             int    `json:"id"`
	Uuid           string `json:"uuid"`
	Name           string `json:"name"`
	TaskTemplateId int    `json:"task_template"`
	Remark         string `json:"remark"`
	PlanType       string `json:"plan_type"`
	TaskTarget     struct {
		Target     []string `json:"target"`
		TargetType string   `json:"target_type"`
	} `json:"task_target"`
	XProcess     []int
	BasicSetting BasicSetting `json:"basic_setting"`
	TaskSetting  TaskSetting  `json:"task_setting"`
	CreatedTime  string       `json:"created_time"`
	UpdatedTime  string       `json:"updated_time"`
}

type PlanOption struct {
	Active         bool         `json:"active"`
	BasicSetting   BasicSetting `json:"basic_setting,omitempty"`
	TaskSetting    TaskSetting  `json:"task_setting,omitempty"`
	ExecRightNow   bool         `json:"exec_right_now"`
	TaskTemplateId int          `json:"task_template_id"`
	TemplateSync   bool         `json:"template_sync"`
	Priority       string       `json:"priority"`
	ProjectId      int          `json:"project_id"`
}

type PlanUpdateOption struct {
	ID           int          `json:"id"`
	BasicSetting BasicSetting `json:"basic_setting,omitempty"`
	TaskSetting  TaskSetting  `json:"task_setting,omitempty"`
	ExecRightNow bool         `json:"exec_right_now"`
}

type PlanFilterOption struct {
	Limit            int            `json:"limit"`
	Offset           int            `json:"offset"`
	ProjectID        int            `json:"project_id"`
	PlanName         []FilterOption `json:"plan_name,omitempty"`
	TaskTemplateName []FilterOption `json:"task_template_name,omitempty"`
	CreatorName      []FilterOption `json:"creator_name"`
}

func newPlan(c *Client, id int) (*Plan, error) {
	var api = fmt.Sprintf("%s%s%d/", c.URI, "api/v2/plan/", id)
	var plan Plan
	err := request(http2.MethodGet, api, c.Token, &plan, http2.TimeOut(c.TimeOut))
	plan.client = c
	return &plan, err
}

func (p *Plan) Exec() error {
	var req = map[string]int{
		"id": p.Id,
	}
	api := p.client.URI + "api/v2/plan/execute/"
	return request(http2.MethodPost, api, p.client.Token, nil, http2.JsonParam(req), http2.TimeOut(p.client.TimeOut))
}

func (p *Plan) Update(opt PlanUpdateOption) error {
	api := p.client.URI + "api/v2/plan/update/"
	err := request(http2.MethodPost, api, p.client.Token, nil, http2.JsonParam(opt), http2.TimeOut(p.client.TimeOut))
	return err
}

// LatestAliveHosts 获取Plan最后一次的执行结果中，存活的主机Hosts
func (p *Plan) LatestAliveHosts() ([]Host, error) {
	for _, xpId := range p.XProcess { // 遍历xProcess，获取最新的执行完毕的id
		xp, err := p.client.XProcess(xpId)
		if err != nil {
			return nil, err
		}
		if xp.Status == XProcessStatusFinished { // 如果完成
			return xp.HostResults(ResultTypeHost, 0, 0)
		}
	}
	return []Host{}, errors.New("没有已完成的XProcess")
}

func (c *Client) PlanFilter(options ...PlanFilterOption) (int64, []Plan, error) {
	var option = PlanFilterOption{
		Limit:     0,
		Offset:    0,
		ProjectID: 1,
	}
	if len(options) == 1 {
		option = options[0]
	}
	type resp struct {
		Count  int64  `json:"count"`
		Result []Plan `json:"result"`
	}
	var result resp
	api := fmt.Sprintf("%sapi/v2/plan/filter/", c.URI)
	err := request(http2.MethodPost, api, c.Token, &result, http2.JsonParam(option), http2.TimeOut(c.TimeOut))
	return result.Count, result.Result, err
}
